package com.ebt.m.customer.ui;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.model.GetObjectRequest;
import com.alibaba.sdk.android.oss.model.GetObjectResult;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.ebt.m.AppContext;
import com.ebt.m.AppInitService;
import com.ebt.m.R;
import com.ebt.m.commons.utils.NetUtils;
import com.ebt.m.commons.utils.RxUtil;
import com.ebt.m.commons.widgets.BaseRxActivity;
import com.ebt.m.customer.constant.CustomerConstant;
import com.ebt.m.customer.model.BeanCustomerTapeWrapper;
import com.ebt.m.customer.model.CustomerTapeJsonWrapper;
import com.ebt.m.customer.net.http.OSSUploader;
import com.ebt.m.customer.net.json.CustomerNoteDetailJson;
import com.ebt.m.customer.net.json.CustomerNoteJson;
import com.ebt.m.customer.net.json.CustomerTapeJson;
import com.ebt.m.customer.util.AttachmentUtil;
import com.ebt.m.customer.util.DisplayUtil;
import com.ebt.m.customer.util.RecordManager;
import com.ebt.m.customer.util.ToastUtil;
import com.ebt.m.customer.view.RecorderView;
import com.ebt.m.customer.view.RecorderWrapper;
import com.ebt.m.customer.view.TapeView;
import com.ebt.m.data.entity.EntityCustomerNote;
import com.ebt.m.data.rxModel.api.EBTAPI;
import com.ebt.m.homepage.CustomerEvent;
import com.ebt.m.utils.DataValidation;
import com.ebt.m.utils.DateUtils;
import com.ebt.m.utils.UIHelper;
import com.ebt.m.widget.MaterialishProgressDialog;
import com.jakewharton.rxbinding2.view.RxView;

import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;


/**
 * 进入此页面时，根据url检测录音是否存在，如果不存在，弹出对话框进行下载
 * 此界面需要被复用，两种模式：
 * <p>
 * 1.新建笔记
 * 2.编辑笔记
 *
 * @author Rick.Wang
 */
public class ActivityCustomerNote extends BaseRxActivity implements RecorderView.OnRecoderClickListener {

    public static final int STATE_ADD = 1;
    public static final int STATE_EDIT = 2;
    public static final int STATE_DELETE = 3;
    public static final int STATE_SAME = 4;
    public static final int STATE_ABORT = 5;

    //values
    private Intent mGetIntent;
    private String mCustomerUuid;

    private String mNoteUuid;
    private String mNoteMode;

    private ScrollView mScrollView;
    private EditText mEditText;
    private TextView mTextViewTime;
    private LinearLayout mContainer;
    private RecorderView mRecorderView;
    private TextView mTextViewToast;
    private TextView mTextViewCount;
    private RelativeLayout mRelativeLayoutToast;
    private int mTapeViewMarginPx = 0;
    private RecorderWrapper mRecorderWrapper;
    private RecordManager mRecordManager;

    private ArrayList<CustomerTapeJsonWrapper> mTapeWrappers = new ArrayList<>();
    private int mTapeWrappersInitSize = 0;
    private ArrayList<TapeView> mTapeViews;

    private CustomerNoteDetailJson mCustomerNoteDetailJson;
    private String mNoteOrgDescription;
    private EBTAPI ebtapi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        OSSUploader.init(this.getApplicationContext());
        initWindow();
        initViews();
        initValues();
    }

    public void initWindow() {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
    }

    public void initViews() {
        setContentView(R.layout.activity_customer_note);
        mScrollView = (ScrollView) this.findViewById(R.id.scrollView);
        mEditText = (EditText) this.findViewById(R.id.fragment_customer_note_add_edit_text);
        mTextViewTime = (TextView) this.findViewById(R.id.fragment_customer_note_add_time);
        mContainer = (LinearLayout) this.findViewById(R.id.fragment_customer_note_add_linearlayout);
        mRecorderView = (RecorderView) this.findViewById(R.id.recorder_view);
        mTextViewToast = (TextView) this.findViewById(R.id.toast_textview);
        mTextViewCount = (TextView) this.findViewById(R.id.countdown_textview);
        mRelativeLayoutToast = (RelativeLayout) this.findViewById(R.id.toast_container);

        mRecorderView.setVisibility(View.VISIBLE);
        mRecorderView.setOnRecoderClickListener(this);
        mTapeViewMarginPx = DisplayUtil.dip2px(this, 4);
        mMaxMessageWidth = getMaxMessageWidth();
        RxView.clicks(findViewById(R.id.btn_cancel))
                .throttleFirst(500, TimeUnit.MILLISECONDS)
                .subscribe(aVoid -> {
                    onBackPressed();
                });
        RxView.clicks(findViewById(R.id.btn_done))
                .throttleFirst(500, TimeUnit.MILLISECONDS)
                .subscribe(aVoid -> {
                    pressDone();
                });


    }

    private int getMaxMessageWidth() {
        return (int) (0.7 * DisplayUtil.getScreenWidth(this));
    }

    public void initValues() {
        ebtapi = AppInitService.getEbtApi();
        mGetIntent = getIntent();
        if (mGetIntent != null) {
            mCustomerUuid = mGetIntent.getStringExtra(CustomerConstant.CUSTOMER_UUID);
            mNoteUuid = mGetIntent.getStringExtra(CustomerConstant.CustomerNote.UUID);
            mNoteMode = mGetIntent.getStringExtra(CustomerConstant.CustomerNote.MODE);
            String defaultValue = mGetIntent.getStringExtra(CustomerConstant.CUSTOMER_DETAIL_NOTE_DEFAULT_VALUE);
            if (!DataValidation.isEmpty(defaultValue)) {
                mEditText.setText(defaultValue);
                mEditText.setSelection(mEditText.getText().length());
            }
        }
        mRecordManager = RecordManager.getInstance().setAppContext((AppContext) (getApplicationContext()));
        mRecorderWrapper = RecorderWrapper.getInstance();

        if (mNoteMode.equals(CustomerConstant.CustomerNote.MODE_ADD)) {
            mTextViewTime.setText((DateUtils.dateTime2String(DateUtils.getCurrentTimestampInSecondToDate())));
            mCustomerNoteDetailJson = new CustomerNoteDetailJson();
            mCustomerNoteDetailJson.data = new CustomerNoteJson();
        } else {
            if (TextUtils.isEmpty(mNoteUuid)) {
                ToastUtil.showToast("出错了，笔记id为空");
            } else {
                ebtapi.getNoteContentByCustomerId(mNoteUuid).compose(RxUtil.rxTransformer(this)).subscribe(getCustomerNoteContentSubscriber());
            }
        }
        requestRecorderPermission();
    }

    /**
     * TapeView的回调
     */
    private TapeView.TapeOperate mTapeViewOperatorCallback = new TapeView.TapeOperate() {
        @Override
        public void onTapeToDelete(TapeView view, BeanCustomerTapeWrapper tapeWrapper) {
            if (tapeWrapper == null) {
                return;
            }

            if (tapeWrapper.getState() == BeanCustomerTapeWrapper.State.ADD) {
                removeTapeUuidFromList(tapeWrapper.getTape().getUuid(), mTapeWrappers, false);
            } else {
                //内存删除
                removeTapeUuidFromList(tapeWrapper.getTape().getUuid(), mTapeWrappers, true);
            }
            view.setVisibility(View.GONE);
        }

        @Override
        public void onTapeToPlay(TapeView view, BeanCustomerTapeWrapper tapeWrapper, float progress) {
            boolean isPlaying = false;
            try {
                isPlaying = mRecorderWrapper.isPlaying();
            } catch (IllegalStateException e) {
                e.printStackTrace();
                mRecorderWrapper = null;
                mRecorderWrapper = RecorderWrapper.getInstance();
            }
            if (isPlaying) {
                mRecorderWrapper.releasePlayer();
            }

            mRecorderWrapper.playRecordFile(
                    AttachmentUtil.netPathToLocalPath(
                            tapeWrapper.getTape().getFilePath(), CustomerConstant.Recorder.DIR_PATH));
            mRecorderWrapper.setPlayerOnCompletionListener(view);
        }

        @Override
        public void onTapeToPause(TapeView view, BeanCustomerTapeWrapper tapeWrapper, float progress) {
            mRecorderWrapper.pausePlayRecordFile();
        }
    };

    private void removeTapeUuidFromList(String uuid, ArrayList<CustomerTapeJsonWrapper> listTapeWraps, boolean setFlag) {
        if (TextUtils.isEmpty(uuid) || listTapeWraps == null) {
            return;
        }
        int size = listTapeWraps.size();
        for (int i = 0; i < size; i++) {
            if (uuid.equals(listTapeWraps.get(i).getTape().getUuid())) {
                if (setFlag) {
                    listTapeWraps.get(i).setState(CustomerTapeJsonWrapper.State.DELETE);
                } else {
                    listTapeWraps.remove(i);
                }
                break;
            }
        }
    }

    private Observer<CustomerNoteDetailJson> getCustomerNoteContentSubscriber() {
        return new Observer<CustomerNoteDetailJson>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onComplete() {
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
                UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));

            }

            @Override
            public void onNext(CustomerNoteDetailJson customerNoteDetailJson) {
                if (customerNoteDetailJson == null) {
                    return;
                }
                if (customerNoteDetailJson.error != null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteDetailJson.error == null) {
                    if (customerNoteDetailJson.data == null) {
                        return;
                    } else {
                        showNoteContent(customerNoteDetailJson);
                    }
                }
            }
        };
    }

    private void showNoteContent(CustomerNoteDetailJson customerNoteDetailJson) {

        mCustomerNoteDetailJson = customerNoteDetailJson;
        if (customerNoteDetailJson == null || customerNoteDetailJson.data == null) {
            ToastUtil.showToast("笔记内容为空");
            return;
        }

        //编辑模式，将原来的text设定到EditText中
        mEditText.setText(customerNoteDetailJson.data.description);
        mNoteOrgDescription = customerNoteDetailJson.data.description;

        if (customerNoteDetailJson.data.description != null) {
            mEditText.setSelection(customerNoteDetailJson.data.description.length());
        }

        //设置显示时间
        if (customerNoteDetailJson.data.createTime != null) {
            mTextViewTime.setText(DateUtils.dateTime2String(
                    DateUtils.parseTimestampInSecondToDate(customerNoteDetailJson.data.createTime)));
        }
        showTapes(customerNoteDetailJson.data.listCustomerNoteTape);
    }

    private void showTapes(List<CustomerTapeJson> listCustomerNoteTape) {
        //解析tape
        ArrayList<CustomerTapeJsonWrapper> tapeWrappers = getTapeData(listCustomerNoteTape);
        ArrayList<CustomerTapeJsonWrapper> tapeWrappersToDownload = new ArrayList<>();

        for (CustomerTapeJsonWrapper item : tapeWrappers) {
            if (item == null || item.getTape() == null) {
                continue;
            }
            if (TextUtils.isEmpty(item.getTape().filePath)) {
                continue;
            }

            if (AttachmentUtil.isPathFromNet(item.getTape().filePath)) {
                String localPath = AttachmentUtil.netPathToLocalPath(item.getTape().filePath, CustomerConstant.Recorder.DIR_PATH);
                if (!new File(localPath).exists()) {
                    //添加待下载
                    tapeWrappersToDownload.add(item);
                    continue;
                } else {
                    mTapeWrappers.add(item);
                }
            } else {
                if (!new File(item.getTape().filePath).exists()) {
                    continue;
                } else {
                    mTapeWrappers.add(item);
                }
            }
        }

        //不需要下载
        if (tapeWrappersToDownload.size() == 0) {
            showAllTapeViews();
        } else {
            //先下载toDownload的部分
            downloadAllFromAli(tapeWrappersToDownload, mapDownloadUrls);
        }
    }

    private void downloadTapesResult(ArrayList<CustomerTapeJsonWrapper> tapeWrappersToDownload, HashMap<String, String> map) {
        dismissMaterialishProgressDialog();
        int[] result = checkDownMapState(map);
        if (result[1] > 0) {
            ToastUtil.showToast(String.valueOf(result[1]) + "个录音下载失败");
        }
        if (tapeWrappersToDownload == null) {
            return;
        }
        for (CustomerTapeJsonWrapper item : tapeWrappersToDownload) {
            if (map.containsKey(item.getTape().filePath)
                    && CustomerConstant.Recorder.DOWNLOAD_FLAG_SUCCESS.equals(map.get(item.getTape().filePath))) {
                mTapeWrappers.add(item);
            }
        }
//        mTapeWrappers.add(item);
        showAllTapeViews();
    }

    private void showAllTapeViews() {
        if (mTapeWrappers != null) {
            mTapeWrappersInitSize = mTapeWrappers.size();
        }

        mTapeViews = genTapeViews(mTapeWrappers);
        showTapeViews(mTapeViews, mContainer);
    }

    private void showTapeViews(ArrayList<TapeView> tapeViews, ViewGroup container) {
        if (tapeViews == null) {
            return;
        }
        for (TapeView view : tapeViews) {
            showTapeView(view, container);
        }
    }

    private void showTapeView(TapeView tapeView, ViewGroup container) {
        if (tapeView == null) {
            return;
        }
        container.addView(tapeView);
    }

    private ArrayList<TapeView> genTapeViews(ArrayList<CustomerTapeJsonWrapper> listTapeWrappers) {
        ArrayList<TapeView> tapeViews = new ArrayList<>();
        if (listTapeWrappers == null) {
            return tapeViews;
        }
        for (CustomerTapeJsonWrapper tapeWrapper : listTapeWrappers) {
            tapeViews.add(genTapeView(tapeWrapper, mTapeViewOperatorCallback));
        }
        return tapeViews;
    }

    private ArrayList<CustomerTapeJsonWrapper> getTapeData(List<CustomerTapeJson> listCustomerNoteTape) {
        ArrayList<CustomerTapeJsonWrapper> tapeWrappers = new ArrayList<>();
        tapeWrappers.addAll(wrapTapes(listCustomerNoteTape));
        return tapeWrappers;
    }

    private List<CustomerTapeJsonWrapper> wrapTapes(List<CustomerTapeJson> tapes) {
        List<CustomerTapeJsonWrapper> tapeWrappers = new ArrayList<>();
        if (tapes != null) {
            for (CustomerTapeJson tape : tapes) {
                tapeWrappers.add(wrapTape(tape));
            }
        }
        return tapeWrappers;
    }

    private CustomerTapeJsonWrapper wrapTape(CustomerTapeJson tape) {
        return new CustomerTapeJsonWrapper(tape, CustomerTapeJsonWrapper.State.ORIGINAL);
    }

    private void pressDone() {
        Object[] o = getUltimateInfoAndState();
        if (o != null && o.length == 3) {
            CustomerNoteDetailJson customerNoteDetailJson = (CustomerNoteDetailJson) o[0];
            ArrayList<CustomerTapeJsonWrapper> tapeWrappers = (ArrayList<CustomerTapeJsonWrapper>) o[1];

            switch ((int) o[2]) {
                case STATE_ADD:
                    if (!NetUtils.isNetworkAvailable(this)) {
                        ToastUtil.showToast(getString(R.string.network_fail));
                        return;
                    }
                    //上传新笔记
                    if (customerNoteDetailJson != null) {
                        if (customerNoteDetailJson.data == null) {
                            customerNoteDetailJson.data = new CustomerNoteJson();
                        }
                        if (tapeWrappers != null) {
                            List<CustomerTapeJson> list = new ArrayList<>();
                            mapUrls.clear();
                            mapStates.clear();
                            for (CustomerTapeJsonWrapper item : tapeWrappers) {
                                if (item.getTape() != null) {
                                    list.add(item.getTape());
                                    mapUrls.put(item.getTape().filePath, "");
                                    mapStates.put(item.getTape().filePath, STATE_ADD);
                                }
                            }
                            customerNoteDetailJson.data.listCustomerNoteTape = list;
                            //上传到阿里云
                            uploadAllToAli(true, customerNoteDetailJson.data, mapStates, mapUrls);
                        } else {
                            //直接上传到服务器，不用上传到阿里云
                            ebtapi.createNote(customerNoteDetailJson.data).compose(RxUtil.rxTransformer(this)).subscribe(getCustomerNoteCUDSubscriber("创建"));
                        }
                    }
                    break;
                case STATE_EDIT:
                    if (!NetUtils.isNetworkAvailable(this)) {
                        ToastUtil.showToast(getString(R.string.network_fail));
                        return;
                    }
                    //更新笔记
                    CustomerNoteJson json = new CustomerNoteJson();
                    json.description = customerNoteDetailJson.data.description;
                    json.noteId = customerNoteDetailJson.data.noteId;
                    json.customerId = mCustomerUuid;

                    List<CustomerTapeJson> listCustomerNoteTape = new ArrayList<>();

                    mapUrls.clear();
                    mapStates.clear();

                    for (CustomerTapeJsonWrapper wrapper : mTapeWrappers) {
                        switch (wrapper.getState()) {
                            case ORIGINAL:
                                //原有，如果是以本地路径开头的，则添加上
                                if (!AttachmentUtil.isPathFromNet(wrapper.getTape().filePath)) {
                                    mapUrls.put(wrapper.getTape().filePath, "");
                                    mapStates.put(wrapper.getTape().filePath, CustomerTapeJsonWrapper.State.ORIGINAL.ordinal());
                                }
                                listCustomerNoteTape.add(wrapper.getTape());
                                break;
                            case ADD:
                                mapUrls.put(wrapper.getTape().filePath, "");
                                mapStates.put(wrapper.getTape().filePath, STATE_ADD);
                                listCustomerNoteTape.add(wrapper.getTape());
                                break;
                            case DELETE:
                                //TODO
                                //这里需要将阿里云上的录音删除
                                break;
                        }
                    }

                    json.listCustomerNoteTape = listCustomerNoteTape;
                    if (json.listCustomerNoteTape != null && json.listCustomerNoteTape.size() > 0 && mapUrls.size() > 0) {
                        //上传到阿里云
                        uploadAllToAli(false, json, mapStates, mapUrls);
                    } else {
                        if (TextUtils.isEmpty(json.description) && (listCustomerNoteTape == null || listCustomerNoteTape.size() == 0)) {
                            ebtapi.deleteNoteById(json.noteId).compose(RxUtil.rxTransformer(this)).subscribe(getNoteDeleteSubscriber());
                        } else {
                            ebtapi.updateNote(json).compose(RxUtil.rxTransformer(this)).subscribe(getCustomerNoteCUDSubscriber("更新"));
                        }
                    }
                    break;
                case STATE_DELETE:
                    if (!NetUtils.isNetworkAvailable(this)) {
                        ToastUtil.showToast(getString(R.string.network_fail));
                        return;
                    }
                    ToastUtil.showToast("删除笔记");
                    deleteOneNote(mNoteUuid);
                    break;
                case STATE_SAME:
                    ToastUtil.showToast("笔记未修改");
                    onBackPressed();
                    break;
                case STATE_ABORT:
                    ToastUtil.showToast("笔记为空");
                    onBackPressed();
                    break;
            }
        }
    }

    private Observer<CustomerNoteDetailJson> getNoteDeleteSubscriber() {

        return new Observer<CustomerNoteDetailJson>() {

            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onComplete() {
            }

            @Override
            public void onError(Throwable e) {
                UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
            }

            @Override
            public void onNext(CustomerNoteDetailJson customerNoteCRUDRetJson) {
                if (customerNoteCRUDRetJson == null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteCRUDRetJson.error != null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteCRUDRetJson.error == null) {
                    if (customerNoteCRUDRetJson.data == null) {
                        UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                        return;
                    } else {
                        EventBus.getDefault().post(new EntityCustomerNote());
                        EventBus.getDefault().post(new CustomerEvent());
                        onBackPressed();
                    }
                }
            }
        };
    }

    private void uploadAllToAli(boolean create, CustomerNoteJson entity,
                                HashMap<String, Integer> mapStates,
                                HashMap<String, String> mapUrls) {
        showMaterialishProgressDialog("正在上传录音");
        List<CustomerTapeJson> list = entity.listCustomerNoteTape;

        int i = 0;
        for (CustomerTapeJson item : list) {
            if (mapUrls.containsKey(item.filePath) && TextUtils.isEmpty(mapUrls.get(item.filePath))) {
                i++;
                uploadToAli(create, item.filePath, entity, mapStates, mapUrls);
            }
        }
        if (i == 0) {
            setMaterialishProgressDialogText("正在上传笔记");
            ebtapi.createNote(entity).compose(RxUtil.rxTransformer(this)).subscribe(getCustomerNoteCUDSubscriber(create ? "创建" : "更新"));
        }
    }

    private void uploadToAli(boolean create, String tapeLocalPath, CustomerNoteJson entity, HashMap<String, Integer> mapStates, HashMap<String, String> mapUrls) {
        OSSUploader.uploadTape(tapeLocalPath, new OnOSSUploadResponseListener(create, entity, tapeLocalPath, mapStates, mapUrls));
    }

    private void downloadAllFromAli(ArrayList<CustomerTapeJsonWrapper> tapeWrappersToDownload,
                                    HashMap<String, String> mapDownloadUrls) {
        if (tapeWrappersToDownload == null || tapeWrappersToDownload.size() == 0) {
            return;
        }
        showMaterialishProgressDialog("正在下载录音");

        //先将所有需要下载的url都添加到map中
        for (CustomerTapeJsonWrapper item : tapeWrappersToDownload) {
            mapDownloadUrls.put(item.getTape().filePath, "");
        }

        //开始下载
        for (CustomerTapeJsonWrapper item : tapeWrappersToDownload) {
            if (mapDownloadUrls.containsKey(item.getTape().filePath)
                    && TextUtils.isEmpty(mapDownloadUrls.get(item.getTape().filePath))) {
                downloadFromAli(tapeWrappersToDownload, item.getTape().filePath, mapDownloadUrls);
            }
        }
    }

    private void downloadFromAli(ArrayList<CustomerTapeJsonWrapper> tapeWrappersToDownload,
                                 String tapeNetUrl, HashMap<String, String> mapDownloadUrls) {
        OSSUploader.downloadTape(AttachmentUtil.getLastFileNameByUrl(tapeNetUrl),
                new OnOSSDownloadResponseListener(tapeWrappersToDownload, tapeNetUrl, mapDownloadUrls));
    }

    private HashMap<String, Integer> mapStates = new HashMap<>();
    private HashMap<String, String> mapUrls = new HashMap<>();
    private HashMap<String, String> mapDownloadUrls = new HashMap<>();

    private class OnOSSUploadResponseListener implements OSSCompletedCallback<PutObjectRequest, PutObjectResult> {

        private HashMap<String, Integer> mapStates;
        private HashMap<String, String> mapUrls;
        private boolean create;
        private CustomerNoteJson entity;
        private String localPath;

        /**
         * 使用 create 接口？
         *
         * @param create
         * @param mapStates
         * @param mapUrls
         */
        public OnOSSUploadResponseListener(boolean create, CustomerNoteJson entity, String localPath, HashMap<String, Integer> mapStates, HashMap<String, String> mapUrls) {
            this.create = create;
            this.entity = entity;
            this.localPath = localPath;
            this.mapStates = mapStates;
            this.mapUrls = mapUrls;
        }

        @Override
        public void onSuccess(PutObjectRequest putObjectRequest, PutObjectResult putObjectResult) {
            if (putObjectRequest != null) {
                String url = OSSUploader.getPublicUrl(putObjectRequest.getBucketName(), putObjectRequest.getObjectKey());
                String[] netPaths = url.split("/");
                if (netPaths != null && netPaths.length > 0) {
                    String fileNameNet = netPaths[netPaths.length - 1];
                    if (!TextUtils.isEmpty(fileNameNet)) {
                        String[] localPaths = localPath.split(File.separator);
                        String fileNameLocal = null;
                        if (localPaths != null && localPaths.length > 0) {
                            fileNameLocal = localPaths[localPaths.length - 1];
                        }
                        if (fileNameNet.equals(fileNameLocal)) {
                            mapUrls.put(localPath, url);
                        }
                    }
                }

                List<CustomerTapeJson> list = entity.listCustomerNoteTape;
                for (CustomerTapeJson json : list) {
                    if (localPath.equals(json.filePath)) {
                        json.filePath = url;
                        break;
                    }
                }

                if (checkMapFull(mapUrls)) {
                    if (create) {
                        ebtapi.createNote(entity).compose(RxUtil.rxTransformer(ActivityCustomerNote.this)).subscribe(getCustomerNoteCUDSubscriber("创建"));
                    } else {
                        ebtapi.updateNote(entity).compose(RxUtil.rxTransformer(ActivityCustomerNote.this)).subscribe(getCustomerNoteCUDSubscriber("更新"));
                    }
                    mapUrls.clear();
                }
            }
        }

        @Override
        public void onFailure(PutObjectRequest putObjectRequest, ClientException e, ServiceException e1) {
            dismissMaterialishProgressDialog();
            ToastUtil.showToast("录音上传失败");
            // 请求异常
            if (e != null) {
                // 本地异常如网络异常等
                e.printStackTrace();
            }
            if (e1 != null) {
                // 服务异常
                Log.e("ErrorCode", e1.getErrorCode());
                Log.e("RequestId", e1.getRequestId());
                Log.e("HostId", e1.getHostId());
                Log.e("RawMessage", e1.getRawMessage());
            }
        }
    }

    private class OnOSSDownloadResponseListener implements OSSCompletedCallback<GetObjectRequest, GetObjectResult> {

        private HashMap<String, String> mapDownloadUrls;
        private String netPath;
        private ArrayList<CustomerTapeJsonWrapper> tapeWrappersToDownload;

        public OnOSSDownloadResponseListener(ArrayList<CustomerTapeJsonWrapper> tapeWrappersToDownload, String netPath, HashMap<String, String> mapDownloadUrls) {
            this.tapeWrappersToDownload = tapeWrappersToDownload;
            this.netPath = netPath;
            this.mapDownloadUrls = mapDownloadUrls;
        }

        @Override
        public void onSuccess(GetObjectRequest getObjectRequest, GetObjectResult getObjectResult) {
            //1.将下载的文件，按照对应的路径进行存储
            InputStream inputStream = getObjectResult.getObjectContent();
            String localPath = AttachmentUtil.netPathToLocalPathWithoutCareExist(netPath, CustomerConstant.Recorder.DIR_PATH);
            File targetFile = new File(localPath);
            if (targetFile.exists()) {
                targetFile.delete();
            }
            try {
                inputStreamToFile(inputStream, targetFile);
                //2.标记已经下载
                mapDownloadUrls.put(netPath, CustomerConstant.Recorder.DOWNLOAD_FLAG_SUCCESS);//标记此url已经被下载
            } catch (Exception e) {
                e.printStackTrace();
                targetFile.delete();
                mapDownloadUrls.put(netPath, CustomerConstant.Recorder.DOWNLOAD_FLAG_FAIL);
            }
            //3.检查是否已经完成
            if (checkMapFull(mapDownloadUrls)) {
                downloadTapesResult(tapeWrappersToDownload, mapDownloadUrls);
            }
        }

        @Override
        public void onFailure(GetObjectRequest getObjectRequest, ClientException e, ServiceException e1) {
            mapDownloadUrls.put(netPath, CustomerConstant.Recorder.DOWNLOAD_FLAG_FAIL);
            if (checkMapFull(mapDownloadUrls)) {
                downloadTapesResult(tapeWrappersToDownload, mapDownloadUrls);
            }

            // 请求异常
            if (e != null) {
                // 本地异常如网络异常等
                e.printStackTrace();
            }
            if (e1 != null) {
                // 服务异常
                Log.e("ErrorCode", e1.getErrorCode());
                Log.e("RequestId", e1.getRequestId());
                Log.e("HostId", e1.getHostId());
                Log.e("RawMessage", e1.getRawMessage());
            }
        }
    }

    public void inputStreamToFile(InputStream ins, File file) throws Exception {
        OutputStream os = new FileOutputStream(file);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
    }

    private boolean checkMapFull(HashMap<String, String> map) {
        if (map == null) {
            return false;
        }
        int size = map.size();
        int i = 0;
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            if (TextUtils.isEmpty(entry.getValue().toString())) {
                return false;
            } else {
                i = i + 1;
            }
        }
        return (size == i);
    }

    private int[] checkDownMapState(HashMap<String, String> map) {
        int success = 0;
        int fail = 0;
        if (map == null) {
            return new int[]{success, fail};
        }

        int size = map.size();
        int i = 0;
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            if (entry.getValue() == null) {
                fail++;
                continue;
            }
            if (CustomerConstant.Recorder.DOWNLOAD_FLAG_FAIL.equals(entry.getValue().toString())) {
                fail++;
            } else {
                success++;
            }
        }
        return new int[]{success, fail};
    }

    //显示等待对话框
    private MaterialishProgressDialog materialishProgressDialog;

    private void showMaterialishProgressDialog(String message) {
        if (materialishProgressDialog == null) {
            materialishProgressDialog = new MaterialishProgressDialog
                    .Builder(this)
                    .setShowTitle(false)
                    .setShowButtons(false)
                    .setCancelable(false)
                    .setCanceledOnTouchOutside(false)
                    .setContentText(message)
                    .create();
        }
        materialishProgressDialog.show();
    }

    private void setMaterialishProgressDialogText(String message) {
        if (materialishProgressDialog == null) {
            materialishProgressDialog = new MaterialishProgressDialog
                    .Builder(this)
                    .setShowTitle(false)
                    .setShowButtons(false)
                    .setCancelable(false)
                    .setCanceledOnTouchOutside(false)
                    .setContentText(message)
                    .create();
            materialishProgressDialog.show();
        } else {
            materialishProgressDialog.setMessage(message);
            if (!materialishProgressDialog.isShowing()) {
                materialishProgressDialog.show();
            }
        }
    }

    private void dismissMaterialishProgressDialog() {
        if (materialishProgressDialog != null) {
            materialishProgressDialog.dismiss();
        }
    }

    private void deleteOneNote(String noteUuid) {
        ebtapi.deleteNoteById(noteUuid).compose(RxUtil.rxTransformer(this)).subscribe(getCustomerNoteCUDSubscriber("删除"));
    }

    private Observer<CustomerNoteDetailJson> getCustomerTapeDeleteSubscriber() {
        return new Observer<CustomerNoteDetailJson>() {

            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onComplete() {
            }

            @Override
            public void onError(Throwable e) {
                UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
            }

            @Override
            public void onNext(CustomerNoteDetailJson customerNoteCRUDRetJson) {
                if (customerNoteCRUDRetJson == null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteCRUDRetJson.error != null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteCRUDRetJson.error == null) {
                    if (customerNoteCRUDRetJson.data == null) {
                        UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                        return;
                    } else {
                        EventBus.getDefault().post(new EntityCustomerNote());
                        onBackPressed();
                    }
                }
            }
        };
    }

    private Observer<CustomerNoteDetailJson> getCustomerNoteCUDSubscriber(String message) {
        return new Observer<CustomerNoteDetailJson>() {

            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onComplete() {
                dismissMaterialishProgressDialog();
            }

            @Override
            public void onError(Throwable e) {
                dismissMaterialishProgressDialog();
                UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
            }

            @Override
            public void onNext(CustomerNoteDetailJson customerNoteCRUDRetJson) {
                dismissMaterialishProgressDialog();
                if (customerNoteCRUDRetJson == null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteCRUDRetJson.error != null) {
                    UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                    return;
                }
                if (customerNoteCRUDRetJson.error == null) {
                    if (customerNoteCRUDRetJson.data == null) {
                        UIHelper.makeToast(ActivityCustomerNote.this, getString(R.string.network_fail));
                        return;
                    } else {
                        ToastUtil.showToast(message + "笔记成功");
                        EventBus.getDefault().post(new EntityCustomerNote());
                        onBackPressed();
                    }
                }
            }
        };
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        overridePendingTransition(R.anim.slide_left_in, R.anim.slide_right_out);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mRecorderWrapper != null) {
            mRecorderWrapper.stopPlayRecordFile();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mRecorderWrapper != null) {
            mRecorderWrapper.stopPlayRecordFile();
        }
    }

    private void toastForPermissionDeny() {
        if (mRelativeLayoutToast != null) {
            mRelativeLayoutToast.setVisibility(View.GONE);
        }
        ToastUtil.showToast("请在\"设置\"中为此应用授予录音权限");
    }

    @Override
    public boolean onRecoderFinish(String simpleFileName) {
        if (checkIfFull()) {
            return true;
        }
        recordFinish(simpleFileName);
        return true;
    }

    private static final int HANDLER_TOAST_HIDE = 2;
    private static final int HANDLER_TOAST_DELAY = 1000;

    private Handler mRecorderHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case HANDLER_TOAST_HIDE:
                    mRelativeLayoutToast.setVisibility(View.GONE);
                    break;
            }
        }
    };

    private void recordFinish(String simpleFileName) {
        mRecorderHandler.removeMessages(HANDLER_TOAST_HIDE);
        mTextViewToast.setText("语音笔记保存成功");
        mRecorderHandler.sendEmptyMessageDelayed(HANDLER_TOAST_HIDE, HANDLER_TOAST_DELAY);
        mRecorderWrapper.stopRecord();

        CustomerTapeJson customerTapeJson = new CustomerTapeJson();
        customerTapeJson.setNoteId(mNoteUuid);
        customerTapeJson.setFilePath(mRecorderWrapper.getRecorderAbsoluteFileName());
        customerTapeJson.setCreateTime(DateUtils.getCurrentTimestampLongInSecond());

        long duration = System.currentTimeMillis() - mTimeStart;
        if (duration > RecorderWrapper.RECORDER_MAX_DURATION) {
            duration = RecorderWrapper.RECORDER_MAX_DURATION;
        }
        customerTapeJson.setTapeDuration(duration);

        addNewTapeData(customerTapeJson, mTapeWrappers);
        TapeView tapeView = genTapeView(new CustomerTapeJsonWrapper(customerTapeJson, CustomerTapeJsonWrapper.State.ADD),
                mTapeViewOperatorCallback);
        mContainer.addView(tapeView, 1);
        mContainer.post(new Runnable() {
            @Override
            public void run() {
                mScrollView.scrollTo(0, (int) tapeView.getY());
            }
        });
    }

    private int mMaxMessageWidth = 0;

    /**
     * 添加一个TapeView
     *
     * @param tapeWrapper
     */
    private TapeView genTapeView(CustomerTapeJsonWrapper tapeWrapper, TapeView.TapeOperate callBack) {
        TapeView tapeView = new TapeView(this);
        tapeView.setTapeOperate(callBack);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(0, mTapeViewMarginPx, 0, mTapeViewMarginPx);
        tapeView.update(tapeWrapper, mMaxMessageWidth);
        tapeView.setLayoutParams(params);
        return tapeView;
    }

    private CustomerTapeJson addNewTapeData(CustomerTapeJson tape, ArrayList<CustomerTapeJsonWrapper> listTapeWraps) {
        if (listTapeWraps == null) {
            listTapeWraps = new ArrayList<>();
        }
        listTapeWraps.add(new CustomerTapeJsonWrapper(tape, CustomerTapeJsonWrapper.State.ADD));
        return tape;
    }

    @Override
    public boolean onRecoderCancel(String simpleFileName, int reason) {
        if (checkIfFull()) {
            return true;
        }
        String message = "";
        switch (reason) {
            case RecorderView.CANCEL_TIME_SHORT:
                message = "语音笔记已取消，录音时间过短，未保存";
                break;
            case RecorderView.CANCEL_MANUALLY:
                message = "语音笔记已取消";
                break;
            case RecorderView.CANCEL_OTHER:
                message = "语音笔记已取消";
                break;
        }
        mTextViewToast.setText(message);
        mRecorderHandler.sendEmptyMessageDelayed(HANDLER_TOAST_HIDE, HANDLER_TOAST_DELAY * 2);
        mRecorderWrapper.stopRecord();//TODO 6.0小米有问题
        mRecorderWrapper.deleteRecordFile(mRecorderWrapper.getRecorderAbsoluteFileName());
        return true;
    }

    @Override
    public void onRecoderCancelTriggerd(String simpleFileName) {
        if (checkIfFull()) {
            return;
        }
        mTextViewToast.setText("松开手指取消语音笔记");
    }

    @Override
    public void onRecoderCancelDismissed(String simpleFileName) {
        if (checkIfFull()) {
            return;
        }
        mTextViewToast.setText("手指上划，取消语音笔记");
    }

    private long mTimeStart;

    private boolean checkIfFull() {
        return mTapeWrappers != null && mTapeWrappers.size() >= 4;
    }

    private int mCurrCountdownSecond = 0;
    private int mPrevCountdownSecond = 0;

    @Override
    public boolean onRecoderStart(String simpleFileName) {
        if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
            if (!mPermissionGrantedGT22) {
                toastForPermissionDeny();
                return false;
            }
        }
        if (checkIfFull()) {
            ToastUtil.showToast("单条笔记最多存储4条录音");
            return true;
        }

        mRecorderHandler.removeMessages(HANDLER_TOAST_HIDE);
        mTextViewToast.setText("手指上划\n取消语音笔记");
        if (mRelativeLayoutToast.getVisibility() == View.GONE) {
            mRelativeLayoutToast.setVisibility(View.VISIBLE);
        }
        mTimeStart = System.currentTimeMillis();

        mCurrCountdownSecond = 0;
        mPrevCountdownSecond = 0;
        mRecorderWrapper.setCountDownListener(new RecorderWrapper.CountDownListener() {
            @Override
            public void onTick(long remainMillisSecond) {
                mCurrCountdownSecond = (int) (remainMillisSecond / 1000);
                if (mCurrCountdownSecond != mPrevCountdownSecond
                        && mCurrCountdownSecond <= RecorderWrapper.RECORDER_COUNT_DOWN_SECOND) {
                    if (mTextViewCount != null) {
                        mTextViewCount.setVisibility(View.VISIBLE);
                        mTextViewCount.setText("剩余" + mCurrCountdownSecond + "秒");
                    }
                    if (mCurrCountdownSecond == RecorderWrapper.RECORDER_COUNT_DOWN_SECOND) {
                        vibrate();
                    }
                }
                mPrevCountdownSecond = mCurrCountdownSecond;
            }

            @Override
            public void onFinish() {
                //结束录音
                MotionEvent upEvent = MotionEvent.obtain(MotionEvent.obtain(
                        SystemClock.uptimeMillis(),
                        SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_UP,
                        mRecorderView.getWidth() / 2,
                        mRecorderView.getHeight() / 2,
                        0));
                mRecorderView.dispatchTouchEvent(upEvent);
                if (mTextViewCount != null) {
                    mTextViewCount.setText("");
                    mTextViewCount.setVisibility(View.GONE);
                }
            }
        });

        try {
            mRecorderWrapper.startRecord(simpleFileName);
        } catch (Exception e) {
            e.printStackTrace();
            toastForPermissionDeny();
            return false;
        }
        return true;
    }

    private void vibrate() {

    }

    private static final int PERMISSION_REQUEST_CODE_RECORD_AUDIO = 99;

    private void requestRecorderPermission() {
        this.getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
                    if (ContextCompat.checkSelfPermission(ActivityCustomerNote.this, Manifest.permission.RECORD_AUDIO)
                            != PackageManager.PERMISSION_GRANTED) {
                        requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
                                PERMISSION_REQUEST_CODE_RECORD_AUDIO);
                    } else {
                        mPermissionGrantedGT22 = true;
                    }
                }
            }
        });
    }

    private boolean mPermissionGrantedGT22 = false;

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE_RECORD_AUDIO) {
            if (grantResults != null && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission Granted
                mPermissionGrantedGT22 = true;
            } else {
                mPermissionGrantedGT22 = false;
                // Permission Denied
                if (mRecorderView != null) {
                    mRecorderView.setVisibility(View.GONE);
                }
            }
        }
    }

    private <E> boolean isListEmpty(List<E> list) {
        return list == null || list.size() == 0;
    }

    private boolean isListTapeSame(List<CustomerTapeJsonWrapper> tapeWrappers) {

        if (tapeWrappers != null) {
            if (tapeWrappers.size() != mTapeWrappersInitSize) {
                return false;
            }
        }

        for (CustomerTapeJsonWrapper wrapper : tapeWrappers) {
            if (wrapper.getState() != CustomerTapeJsonWrapper.State.ORIGINAL) {
                return false;
            }
        }
        return true;
    }

    private Object[] getUltimateInfoAndState() {
        Object[] ultimateCustomerAndChangeState = new Object[3];
        if (mCustomerNoteDetailJson == null) {
            mCustomerNoteDetailJson = new CustomerNoteDetailJson();
        }
        fetchContentIntoNote(mCustomerNoteDetailJson);
        //添加模式
        if (CustomerConstant.CustomerNote.MODE_ADD.equals(mNoteMode)) {
            if (TextUtils.isEmpty(mCustomerNoteDetailJson.data.description) && isListEmpty(mTapeWrappers)) {
                ultimateCustomerAndChangeState[2] = STATE_ABORT;
            } else {
                ultimateCustomerAndChangeState[2] = STATE_ADD;
                if (TextUtils.isEmpty(mCustomerUuid)) {
                    ultimateCustomerAndChangeState[2] = STATE_ABORT;
                }
                if (mCustomerNoteDetailJson.data.description == null) {
                    mCustomerNoteDetailJson.data.description = "";
                }
                mCustomerNoteDetailJson.data.noteId = mNoteUuid;
            }
        } else {
            //修改模式
            if (TextUtils.isEmpty(mCustomerNoteDetailJson.data.description) && isListEmpty(mTapeWrappers)) {
                ultimateCustomerAndChangeState[2] = STATE_DELETE;
            } else {
                if (mCustomerNoteDetailJson.data.description.equals(mNoteOrgDescription)
                        && isListTapeSame(mTapeWrappers)) {
                    ultimateCustomerAndChangeState[2] = STATE_SAME;
                } else {
                    ultimateCustomerAndChangeState[2] = STATE_EDIT;
                }
            }
        }
        ultimateCustomerAndChangeState[0] = mCustomerNoteDetailJson;
        ultimateCustomerAndChangeState[1] = mTapeWrappers;
        return ultimateCustomerAndChangeState;
    }

    public void fetchContentIntoNote(CustomerNoteDetailJson entity) {
        entity.data.description = mEditText.getText().toString().trim();
        entity.data.customerId = mCustomerUuid;
    }

}
